package volatileTest;

/**
 * volatile测试
 * blog https://www.cnblogs.com/tangyanbo/p/6538488.html
 */
public class VolatileTestMain {

//4332436
//        61876379
    public static void main(String[] args) throws InterruptedException {
        OriginTask originTask = new OriginTask();
        VolatileTask volatileTask = new VolatileTask();
        SynchronizedTask synchronizedTask = new SynchronizedTask();

        Thread originThread = new Thread(originTask);
        Thread volatileThread = new Thread(volatileTask);
        Thread syncThread = new Thread(synchronizedTask);

        //死循环
//        originThread.start();
        Thread.sleep(10);
        System.out.println("originTask "+originTask.i);
        originTask.flag = false;
        Thread.sleep(100);
        System.out.println("originTask "+originTask.i);

        /**
         *   不会死循环 因为volatile变量修饰的变量
         *   java内存分为工作内存和主存
             工作内存：即java线程的本地内存，是单独给某个线程分配的，存储局部变量等，同时也会复制主存的共享变量作为本地
             的副本，目的是为了减少和主存通信的频率，提高效率。
             主存：存储类成员变量等

             可见性是指的是线程访问变量是否是最新值。
             局部变量不存在可见性问题，而共享内存就会有可见性问题，
             因为本地线程在创建的时候，会从主存中读取一个共享变量的副本，且修改也是修改副本，
             且并不是立即刷新到主存中去，那么其他线程并不会马上共享变量的修改。
             因此，线程B修改共享变量后，线程A并不会马上知晓，就会出现上述死循环的问题。

             解决共享变量可见性问题，需要用volatile关键字修饰。
         */
        volatileThread.start();
        Thread.sleep(10);
        System.out.println("volatileTask "+volatileTask.i);
        volatileTask.flag = false;
        Thread.sleep(100);
        System.out.println("volatileTask "+volatileTask.i);
        /**
         * 同步块存在如下语义：
         1.进入同步块，访问共享变量会去读取主存
         2.退出同步块，本地内存对共享变量的修改会立即刷新到主存
         因此上述代码不会出现死循环。
         */
        syncThread.start();
        Thread.sleep(10);
        System.out.println("synchronizedTask "+synchronizedTask.i);
        synchronizedTask.setRunning(false);
        Thread.sleep(100);
        System.out.println("synchronizedTask "+synchronizedTask.i);
/**
 * 原子操作 发现和博客上说的完全不一样
 */
        AtomVolatileTask atomVolatileTask = new AtomVolatileTask();
        Thread atomThread1 = new Thread(atomVolatileTask);
        Thread atomThread2 = new Thread(atomVolatileTask);
        atomThread1.start();
        atomThread2.start();
//        atomThread1.join();
//        atomThread2.join();
        Thread.sleep(2000);
        System.out.println(atomVolatileTask.i);
    }
}
